package mlog

type StdLogger interface {
	Print(v ...interface{})
	Println(v ...interface{})
	Printf(format string, v ...interface{})
}

type LevelLogger interface {
	StdLogger

	Debug(v ...interface{})
	Debugf(format string, v ...interface{})

	Info(v ...interface{})
	Infof(format string, v ...interface{})

	Notice(v ...interface{})
	Noticef(format string, v ...interface{})

	Warning(v ...interface{})
	Warningf(format string, v ...interface{})

	Error(v ...interface{})
	Errorf(format string, v ...interface{})

	Critical(v ...interface{})
	Criticalf(format string, v ...interface{})

	Alert(v ...interface{})
	Alertf(format string, v ...interface{})

	Emergency(v ...interface{})
	Emergencyf(format string, v ...interface{})

	Reload() error
	Close()

	AddHandler(Handler)
}

type Option struct {
	Type         uint8
	File         string
	Levels       []string
	Format       int
	PreventSmart bool
	Json         bool
	Rotate       uint8
}

type Logger struct {
	handlers []Handler
}

func NewNullLogger() (l *Logger) {
	l = &Logger{}

	return
}

func NewLogger(opts ...*Option) (l *Logger) {
	if nil == opts {
		opts = make([]*Option, 0)
	}

	l = NewNullLogger()

	for _, opt := range opts {
		var h Handler = nil
		switch opt.Type {
		case TBare:
			h = NewBareHandler(opt.File)
		case TFile:
			fh := NewFileHandler(opt.File, opt.Format)
			fh.setFormatFlag(opt.Format)
			h = fh
		case TLevel:
			fh := NewLevelHandler(opt.File, opt.Format, opt.Levels...)
			fh.setFormatFlag(opt.Format)
			h = fh
		case TLvRotate:
			fh := NewRotateFileHandler(opt.File, opt.Format, uint8(opt.Rotate))
			fh.AddFilter(LevelFilter(opt.Levels...))
			fh.setFormatFlag(opt.Format)
			h = fh
		case TRFile:
			h = NewRotateFileHandler(opt.File, opt.Format, uint8(opt.Rotate))
		}

		if opt.Json {
			h = NewJsonHandler(h)
		}

		if !opt.PreventSmart {
			h = NewSmartHandler(h)
		}

		l.AddHandler(h)
	}
	return
}

func (l *Logger) AddHandler(h Handler) {
	l.handlers = append(l.handlers, h)
}

func (l *Logger) Print(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(LevelAll, "", v))
	}
}

func (l *Logger) Println(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(LevelAll, "", v))
	}
}

func (l *Logger) Printf(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(LevelAll, format, v))
	}
}

func (l *Logger) Debug(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Debug, "", v))
	}
}

func (l *Logger) Debugf(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Debug, format, v))
	}
}

func (l *Logger) Info(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Info, "", v))
	}
}

func (l *Logger) Infof(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Info, format, v))
	}
}

func (l *Logger) Notice(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Notice, "", v))
	}
}

func (l *Logger) Noticef(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Notice, format, v))
	}
}

func (l *Logger) Warning(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Warning, "", v))
	}
}

func (l *Logger) Warningf(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Warning, format, v))
	}
}

func (l *Logger) Error(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Error, "", v))
	}
}

func (l *Logger) Errorf(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Error, format, v))
	}
}

func (l *Logger) Alert(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Alert, "", v))
	}
}

func (l *Logger) Alertf(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Alert, format, v))
	}
}

func (l *Logger) Critical(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Critical, "", v))
	}
}

func (l *Logger) Criticalf(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Critical, format, v))
	}
}

func (l *Logger) Emergency(v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Emergency, "", v))
	}
}

func (l *Logger) Emergencyf(format string, v ...interface{}) {
	for _, h := range l.handlers {
		h.Log(NewRecord(Emergency, format, v))
	}
}

func (l *Logger) Reload() (err error) {
	for _, h := range l.handlers {
		if err = h.Reload(); nil != err {
			return
		}
	}

	return
}

func (l *Logger) Close() {
	for _, h := range l.handlers {
		h.Close()
	}
}
